package com.tqjc.system.core.pipeline.thread;

import com.tqjc.business.interactivewithscan.entity.Coord;
import com.tqjc.system.common.constant.*;
import com.tqjc.system.common.entity.BO.MoreTaskMaterialBO;
import com.tqjc.system.common.entity.BO.PLCWriteRequestParamBO;
import com.tqjc.system.common.entity.BO.ResponseLabelDataBO;
import com.tqjc.system.common.entity.BO.TaskMaterialBO;
import com.tqjc.system.common.enums.*;
import com.tqjc.system.common.exception.AddTaskException;
import com.tqjc.system.core.pipeline.util.AddTaskUtil;
import com.tqjc.system.core.pipeline.util.ScanUtils;
import com.tqjc.system.core.scan.thread.AsynTankCarScanThread;
import com.tqjc.system.core.threadpool.ThreadPoolManager;
import com.tqjc.system.core.util.DateUtils;
import com.tqjc.system.core.util.PLCHttpsUtils;
import com.tqjc.system.core.util.SpringUtils;
import com.tqjc.system.core.websocket.TaskExecutionWebSocketService;
import com.tqjc.system.system.entity.SysAddDetailTaskEntity;
import com.tqjc.system.system.entity.SysPLCRecordEntity;
import com.tqjc.system.system.entity.SysTaskErrorInfoEntity;
import com.tqjc.system.system.service.SysAddDetailTaskService;
import com.tqjc.system.system.service.SysPLCRecordService;
import com.tqjc.system.system.util.SystemUtils;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;


import java.io.IOException;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReentrantLock;


/**
 * @author 86195
 * @version 1.0
 * @description 天车执行加料任务线程
 * @date 2023/10/18 15:02
 */
@Slf4j
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Data
public class CarDoingAddTaskThread extends AbstrCarDoingAddTaskThread{


    private MoreTaskMaterialBO taskMaterialBO;


    private ReentrantLock lock;

    /**
     * 上一次动作  避让：avoid  移动:move
     */
    private String lastAct;




    /**
     * 二次避让标识
     */
    private boolean secAvoidFlag;


    /**
     * 槽车到位信号  false:未到位   true:已到位
     */
    private boolean tankCarReadyFlag;





    @Override
    public void run() {
        //任务id
        String taskId = taskMaterialBO.getTaskId();

        //0.获取锁
        String workingSpanNo = taskMaterialBO.getWorkingSpanNo();
        String workingCarNo = taskMaterialBO.getCarEnum().getCarNo();
        log.info("任务id：{},工作跨：{},工作天车编号：{},双车加料线程任务开始",taskId,workingSpanNo,workingCarNo);


        //同跨另一台天车key  spanNo +_ + carNo
        String otherKey =  new StringBuilder(workingSpanNo).append("_").append(taskMaterialBO.getCarEnum().getOtherCarNo()).toString();
        SysAddDetailTaskService detailTaskService = SpringUtils.getBean("SysAddDetailTaskService");
        //当前跨天车key    spanNo +_ + carNo
        String currKey = new StringBuilder(workingSpanNo).append("_").append(taskMaterialBO.getCarEnum().getCarNo()).toString();
        CarEnum workingCarEnum = taskMaterialBO.getCarEnum();


        /**
         * 判断天车行车是否冲突   true:没有冲突   false：有冲突
         */
        boolean isConflict;

        //天车信息枚举
        CarPLCInfoEnum carPLCInfoEnum = CarPLCInfoEnum.getCarNoEnum(workingSpanNo, workingCarEnum.getCarNo());
        String macSN = carPLCInfoEnum.getMacSN();

        String otherThreadKey = carPLCInfoEnum.getOtherMacSN();
        CarDoingAddTaskThread otherThread = (CarDoingAddTaskThread) AddTaskConstant.CAR_THREAD_MAP.get(otherThreadKey);

        String tankCarNo = taskMaterialBO.getTankCarNo();
        TankCarNoEnum tankCarNoEnum = TankCarNoEnum.getEnumByCarNo(tankCarNo);
        //槽车参数Map
        Map<String,String> tankCarParamMap = new HashMap(2);
        tankCarParamMap.put(GlobalConstant.STRING_SN,GlobalConstant.TANK_CAR_SN_VAL);

        //天车参数Map
        Map<String,String> carParamMap = new HashMap(2);
        Map<String, String> carSNMap = SystemUtils.Sys_carInfo.get(ConfigConstant.CONFIG_TYPE_CAR_BAK_SN);
        String carSN = carSNMap.get(carPLCInfoEnum.getMacSN());
        carParamMap.put(GlobalConstant.STRING_SN,carSN);

        //监听天车模式参数map
        Map<String,String> modelParamMap = new HashMap(2);
        modelParamMap.put(GlobalConstant.STRING_SN,carSN);
        modelParamMap.put(GlobalConstant.STRING_LABEL,carPLCInfoEnum.getMacSN() + GlobalConstant.CAR_MODEL_LABEL);


        //任务类型
        String taskType;
        //任务地点
        String taskPlace;

        //现在的重量
        float nowWeight;
        //避让位置
        int avoidArray[];

        //另一台车的目标位置
        int otherTargetIndex;
        //当前车的避让位置
        int avoidIndex;
        //之前的槽车重量
        float oldWeight;

        /**
         * 子任务的主键
         */
        Long idKey = null;

        //双车大车运行状态
        boolean carRunningFlag;


        //开始时间
        LocalDateTime startDate;

        //结束时间
        LocalDateTime endDate;

        SysPLCRecordService plcRecordService = SpringUtils.getBean(SysPLCRecordService.class);

        //plc记录状态
        SysPLCRecordEntity plcRecord;

        //读取数据结果
        ResponseLabelDataBO responseLabelDataBO;
        //判断天车是否可以移动
//        try {
//            log.info("判断天车是否可以移动");
//
//            while (true){
//                carParamMap.put(GlobalConstant.STRING_LABEL, macSN + GlobalConstant.MOVE_FINISH_LABEL);
//                boolean moveFlag = Boolean.valueOf(this.getValByLabel(carParamMap));
//                //moveFlag = false;
//                CarProgressLogThread msgThread = CarProgressLogThread.builder().carInfo(carPLCInfoEnum.getMacSN())
//                        .msg("任务id："+taskId + "天车：" + carPLCInfoEnum.getMacSN() + "移动运行已复位" ).build();
//                ThreadPoolManager.getInstance().execute(msgThread);
//                if(!moveFlag){
//                    log.info("天车可以移动");
//
//                    break;
//                }
//                Thread.sleep(5*1000);
//
//            }
//        } catch (Exception e){
//            log.error("任务id：{}双车加料线程任务。运行出错",taskId,e);
//            String errMsg = e.getMessage();
//            if(errMsg == null){
//                errMsg = "双车加料任务运行出错，请查看日志";
//            }
//            errMsg = errMsg.length() > 200 ? errMsg.substring(200) : errMsg;
//            SysAddDetailTaskEntity errEntity = SysAddDetailTaskEntity.builder().idKey(idKey)
//                    .status(TaskStatusEnum.STATUS_ERROR.getStatus()).errMsg(errMsg).build();
//            detailTaskService.updateById(errEntity);
//
//        }


        try {
            while (true){
                //获取一个子任务
                TaskMaterialBO taskMaterial = AddTaskUtil.getTaskMaterial(taskId, workingCarEnum);

                if(taskMaterial == null){
                    taskFinishFlag = true;
                    log.info("任务id：{},工作跨：{},工作天车编号：{},双车加料线程任务。已经没有子任务了",taskId,workingSpanNo,workingCarNo);
                    CarProgressLogThread msgThread = CarProgressLogThread.builder().carInfo(carPLCInfoEnum.getMacSN())
                            .msg("任务id"+taskId + "没有子任务了。天车休息").build();
                    ThreadPoolManager.getInstance().execute(msgThread);
                    //写值移动
                    carRunningFlag = AddTaskUtil.isCarRunningStatus(carSN, carPLCInfoEnum.getMacSN(), carPLCInfoEnum.getOtherMacSN() );
                    if(!carRunningFlag){
                        throw new AddTaskException("双车执行任务时，双车的大车运行状态不是自动,跨区为："+workingSpanNo);
                    }

                    log.info("任务id：{},工作跨：{},工作天车编号：{},双车加料线程任务。开始写值避让位置",taskId,workingSpanNo,workingCarNo);

                    goSafePosition(carPLCInfoEnum);
                    log.info("任务id：{},工作跨：{},工作天车编号：{},双车加料线程任务。结束写值避让位置",taskId,workingSpanNo,workingCarNo);

                    AddTaskUtil.updateCarIndex(currKey,null);
                    while (true){
                        carParamMap.put(GlobalConstant.STRING_LABEL, macSN + GlobalConstant.MOVE_FINISH_LABEL);
                        boolean moveFlag = Boolean.valueOf(this.getValByLabel(carParamMap));
                        carParamMap.put(GlobalConstant.STRING_LABEL,macSN + GlobalConstant.CAR_MOVE_LABEL);
                        boolean carStatusFlag = Boolean.valueOf(this.getValByLabel(carParamMap));

//                        moveFlag = true;
                        if(moveFlag || !carStatusFlag){
                            log.info("任务id：{},工作跨：{},工作天车编号：{},双车加料线程任务。行车已移动到安全位置。得到结果moveFlag是：{}，carStatusFlag是：{}",taskId,workingSpanNo,workingCarNo,moveFlag,carStatusFlag);
                            Object[] carExecuteInfo = carPLCInfoEnum.getPLCInfoArray()[5];
                            //天车动作执行复位
                            PLCWriteRequestParamBO paramBO = PLCWriteRequestParamBO.builder().dataType((Integer) carExecuteInfo[1])
                                    .address((String) carExecuteInfo[0]).macSN(macSN).label((String) carExecuteInfo[2]).build();
                            paramBO.setValue(AddTaskConstant.CAR_FORBID_MOVE);
                            PLCHttpsUtils.write(RemoteURLConstant.URL_WRITEBC,paramBO);
                            log.info("任务id：{},工作跨：{},工作天车编号：{},双车加料线程任务。行车已移动到安全位置。复位完成。得到结果moveFlag是：{}，carStatusFlag是：{}",taskId,workingSpanNo,workingCarNo,moveFlag,carStatusFlag);
                            break;
                        }
                        log.info("任务id：{},工作跨：{},工作天车编号：{},双车加料线程任务。判断行车安全位置是否移动到位",taskId,workingSpanNo,workingCarNo);

                        Thread.sleep(1*1000);

                    }

                    log.info("任务id：{},跨区：{},天车号：{},双车加料线程任务结束",taskId,workingSpanNo,workingCarNo);
                    break;
                }
                idKey = taskMaterial.getIdKey();
                //更新任务状态
                SysAddDetailTaskEntity sysAddDetailTaskEntity = SysAddDetailTaskEntity.builder().idKey(idKey)
                        .status(TaskStatusEnum.STATUS_DOING.getStatus()).carName(macSN).build();
                //异步线程更新数据
                ThreadPoolManager.getInstance().execute(new DataUpdateThread(detailTaskService,sysAddDetailTaskEntity));

                String materialNo = taskMaterial.getWorkinMaterialNo();
                CarProgressLogThread msgThread = CarProgressLogThread.builder().carInfo(carPLCInfoEnum.getMacSN())
                        .msg("天车开始执行单词抓取与放下,"+materialNo + "任务").build();
                ThreadPoolManager.getInstance().execute(msgThread);
                int areaNum = taskMaterial.getAreaNum();
                log.info("任务id：{},工作跨：{},工作天车编号：{},双车加料线程任务。开始获取抓点",taskId,workingSpanNo,workingCarNo);


//                Coord grabPoint = new Coord();
//                if(workingCarNo.equals("1")){
//
//                    grabPoint.setX(999999);
//                }
//
//                if(workingCarNo.equals("2")){
//
//                    grabPoint.setX(111);
//                }




                while (true){
                    //业务逻辑执行
                    //记录PLC表
//                    Coord grabPoint = ScanUtils.getSpanGrabPoint(workingSpanNo, carPLCInfoEnum.getCarNo(), materialNo, areaNum);
                    Coord grabPoint = ScanUtils.getAreaPointBO(workingSpanNo, materialNo, AddTaskConstant.AREA_SCAN_TYPE_SUCK);

                    if(grabPoint == null){
                        log.error("任务id：{},跨区：{},天车号：{},双车加料线程没有获取抓点",taskId,workingSpanNo,workingCarNo);
                        throw new AddTaskException("没有获取抓点");
                    }
                    startDate = LocalDateTime.now();
                    plcRecord = SysPLCRecordEntity.builder().taskId(taskId).relationIdKey(String.valueOf(idKey)).carName(carPLCInfoEnum.getMacSN())
                            .indexInfo(grabPoint.getIndexInfo()).actionInfo(AddTaskConstant.ACT_SUCK).targetInfo("料场："+areaNum).build();
                    plcRecordService.save(plcRecord);
                    Integer otherPosition = AddTaskUtil.getCarIndex(otherKey);
                    //1.判断是否冲突
                    isConflict = comparePosition(workingCarEnum, grabPoint.getX(), otherPosition);
                    if(isConflict){
                        log.info("任务id：{},工作跨：{},工作天车编号：{},双车加料线程任务。抓点移动不冲突",taskId,workingSpanNo,workingCarNo);

                        //不冲突
                        //2.到达抓点，执行抓动作
                        //没有冲突
                        lock.lock();
                        this.lastAct = AddTaskConstant.ACT_MOVE;
                        lock.unlock();
                        AddTaskUtil.updateCarIndex(currKey,grabPoint.getX());
                        taskType = AddTaskConstant.CAR_TASK_TYPE_SUCK;
                        taskPlace = AddTaskConstant.CAR_TASK_PLACE_MATERIAL;

                        msgThread = CarProgressLogThread.builder().carInfo(carPLCInfoEnum.getMacSN()).msg("天车执行抓取动作，没有冲突").build();
                        ThreadPoolManager.getInstance().execute(msgThread);
                        //移动写值操作
                        carRunningFlag = AddTaskUtil.isCarRunningStatus(carSN, carPLCInfoEnum.getMacSN() , carPLCInfoEnum.getOtherMacSN());
//                        carRunningFlag = true;
                        if(!carRunningFlag){
                            throw new AddTaskException("双车执行任务时，双车的大车运行状态不是自动,跨区为："+workingSpanNo);
                        }
                        log.info("任务id：{},工作跨：{},工作天车编号：{},双车加料线程任务。移动写值开始",taskId,workingSpanNo,workingCarNo);
                        this.writeOpt(carPLCInfoEnum,grabPoint,taskType,taskPlace);
                        log.info("任务id：{},工作跨：{},工作天车编号：{},双车加料线程任务。移动写值完成",taskId,workingSpanNo,workingCarNo);

                    } else {
                        //有冲突
                        log.info("任务id：{},工作跨：{},工作天车编号：{},双车加料线程任务。抓点移动冲突",taskId,workingSpanNo,workingCarNo);
                        //1.如果对方是

                        lock.lock();
                        this.lastAct = AddTaskConstant.ACT_AVOID;
                        if(AddTaskConstant.ACT_AVOID.equals(otherThread.getLastAct())){
                            //两个线程同时为避让，生成被动唤醒线程
                            log.info("任务id：{},工作跨：{},工作天车编号：{},双车加料线程任务。抓点移动冲突。生成被动唤醒对方线程",taskId,workingSpanNo,workingCarNo);
                            if(AddTaskUtil.isPassiveThread(workingSpanNo)){
                                msgThread = CarProgressLogThread.builder().carInfo(carPLCInfoEnum.getMacSN())
                                        .msg("天车执行抓动作，冲突，生成被动唤醒对方线程").build();
                                TaskWakeThread taskWakeThread = TaskWakeThread.builder().thread(otherThread).carInfo(carPLCInfoEnum.getOtherDesc()).workSpanNo(workingSpanNo).build();
                                ThreadPoolManager.getInstance().execute(taskWakeThread);
                            }
                        }
                        lock.unlock();
                        AddTaskUtil.updateCarIndex(currKey,grabPoint.getX());
                        otherTargetIndex = AddTaskUtil.getCarIndex(otherKey);
                        //安全距离设置   移动至槽车位置
                        //判断是一号车？ 另一台车的目标位置 - 安全距离  ： 另一台车的目标位置 + 安全距离
                        //int xIndex = tankCarNoEnum.getXIndex();
                        avoidIndex = workingCarEnum.getOtherCarNo().equals(CarEnum.CAR_NO_1.getCarNo()) ? otherTargetIndex - AddTaskConstant.SAFE_DISTANCE :
                                otherTargetIndex + AddTaskConstant.SAFE_DISTANCE;

                        //移动至对方位置的避让位置
                        Coord avoidCoord = new Coord();
                        avoidCoord.setX(avoidIndex);
                        avoidCoord.setY(grabPoint.getY());
                        avoidCoord.setZ(AddTaskConstant.SAFE_HEIGHT_DISTANCE);
                        taskType = AddTaskConstant.CAR_TASK_TYPE_MOVE;
                        taskPlace = AddTaskConstant.CAR_TASK_PLACE_MATERIAL;
                        //移动写值操作
                        carRunningFlag = AddTaskUtil.isCarRunningStatus(carSN, carPLCInfoEnum.getMacSN(), carPLCInfoEnum.getOtherMacSN());
//                        carRunningFlag = true;
                        if(!carRunningFlag){
                            throw new AddTaskException("双车执行任务时，双车的大车运行状态不是自动,跨区为："+workingSpanNo);
                        }
                        log.info("任务id：{},工作跨：{},工作天车编号：{},双车加料线程任务。移动写值开始",taskId,workingSpanNo,workingCarNo);
                        this.writeOpt(carPLCInfoEnum,avoidCoord,taskType,taskPlace);
                        log.info("任务id：{},工作跨：{},工作天车编号：{},双车加料线程任务。移动写值结束",taskId,workingSpanNo,workingCarNo);


                        msgThread = CarProgressLogThread.builder().carInfo(carPLCInfoEnum.getMacSN())
                                .msg("天车执行抓取动作，发生冲突。执行避让动作").build();
                        ThreadPoolManager.getInstance().execute(msgThread);

                        //判断避让动作是否完成
                        while (true){
                            log.info("任务id：{},工作跨：{},工作天车编号：{},双车加料线程任务。抓点冲突中，判断避让动作是否完成",taskId,workingSpanNo,workingCarNo);

                            carParamMap.put(GlobalConstant.STRING_LABEL, macSN + GlobalConstant.MOVE_FINISH_LABEL);

                            boolean moveFlag = Boolean.valueOf(this.getValByLabel(carParamMap));
                            //天车模式flag  false:手动  true:自动
                            boolean modelFlag = Boolean.valueOf(this.getValByLabel(modelParamMap));
//                            while (taskFlag){
//                                log.warn("双车加料线程执行任务时，任务监控点位出现故障");
//                                Thread.sleep(1000*5);
//                            }

                            if(taskFinishFlag){
                                log.error("任务id：{},工作跨：{},工作天车编号：{},双车加料线程任务。抓点冲突中，判断避让动作是否完成。任务标识为已完成",taskId,workingSpanNo,workingCarNo);

                                throw new AddTaskException("双车加料线程执行任务时，任务手动置为完成状态");
                            }

//                            moveFlag = true;
//                            modelFlag = true;
                            if(!modelFlag){
                                //模式为自动时，线程结束
                                log.info("任务id：{},工作跨：{},工作天车编号：{},双车加料线程任务。抓点冲突中，模式切换至手动模式，线程退出",taskId,workingSpanNo,workingCarNo);
                                SysAddDetailTaskEntity updateTaskEntity = SysAddDetailTaskEntity.builder()
                                        .idKey(idKey).status(TaskStatusEnum.STATUS_ERROR.getStatus()).errMsg("天车模式切换至手动模式，任务退出").build();
                                DataUpdateThread.builder().detailTaskService(detailTaskService).sysAddDetailTask(updateTaskEntity).build().start();
                                return;
                            }

                            if(moveFlag){
                                log.info("任务id：{},工作跨：{},工作天车编号：{},双车加料线程任务。抓点冲突中，避让动作完成，开始复位",taskId,workingSpanNo,workingCarNo);

                                Object[] carExecuteInfo = carPLCInfoEnum.getPLCInfoArray()[5];

                                //天车动作运行复位
                                PLCWriteRequestParamBO paramBO = PLCWriteRequestParamBO.builder().dataType((Integer) carExecuteInfo[1])
                                        .address((String) carExecuteInfo[0]).macSN(macSN).label((String) carExecuteInfo[2]).build();
                                paramBO.setValue(AddTaskConstant.CAR_FORBID_MOVE);
                                PLCHttpsUtils.write(RemoteURLConstant.URL_WRITEBC,paramBO);
                                log.info("任务id：{},工作跨：{},工作天车编号：{},双车加料线程任务。抓点冲突中，避让动作完成，复位完成",taskId,workingSpanNo,workingCarNo);
                                break;
                            }
                            Thread.sleep(1*1000);

                        }

                        msgThread = CarProgressLogThread.builder().carInfo(carPLCInfoEnum.getMacSN())
                                .msg("执行抓取动作冲突，准备进入等待").build();
                        ThreadPoolManager.getInstance().execute(msgThread);

                        synchronized (this){
                            //等待唤醒
                            msgThread = CarProgressLogThread.builder().carInfo(carPLCInfoEnum.getMacSN())
                                    .msg("执行抓取动作冲突，进入等待").build();
                            ThreadPoolManager.getInstance().execute(msgThread);
                            this.wait();
                        }
                        lock.lock();
                        this.lastAct = AddTaskConstant.ACT_MOVE;
                        lock.unlock();
                        log.info("任务id：{},工作跨：{},工作天车编号：{},双车加料线程任务。抓点冲突中，线程被唤醒，移动至目标位置",taskId,workingSpanNo,workingCarNo);

                        taskType = AddTaskConstant.CAR_TASK_TYPE_SUCK;
                        taskPlace = AddTaskConstant.CAR_TASK_PLACE_MATERIAL;

                        //移动写值操作
                        carRunningFlag = AddTaskUtil.isCarRunningStatus(carSN, carPLCInfoEnum.getMacSN(), carPLCInfoEnum.getOtherMacSN() );
//                        carRunningFlag = true;
                        if(!carRunningFlag){
                            throw new AddTaskException("双车执行任务时，双车的大车运行状态不是自动,跨区为："+workingSpanNo);
                        }
                        log.info("任务id：{},工作跨：{},工作天车编号：{},双车加料线程任务。移动写值开始",taskId,workingSpanNo,workingCarNo);
                        this.writeOpt(carPLCInfoEnum,grabPoint,taskType,taskPlace);
                        log.info("任务id：{},工作跨：{},工作天车编号：{},双车加料线程任务。移动写值结束",taskId,workingSpanNo,workingCarNo);


                        msgThread = CarProgressLogThread.builder().carInfo(carPLCInfoEnum.getMacSN())
                                .msg("执行抓取动作冲突,线程被唤醒，移动至抓点位置结束").build();
                        ThreadPoolManager.getInstance().execute(msgThread);

                    }


                    //2.判断槽车是否到位
                    if(!tankCarReadyFlag){
                        msgThread = CarProgressLogThread.builder().carInfo(carPLCInfoEnum.getMacSN())
                                .msg("判断槽车是否移动到位").build();
                        ThreadPoolManager.getInstance().execute(msgThread);
                        while (true){
                            log.info("任务id：{},工作跨：{},工作天车编号：{},双车加料线程任务。判断槽车是否到位",taskId,workingSpanNo,workingCarNo);

                            boolean tankCarScanActFinish = ScanUtils.getTankCarScanActFinish(tankCarNoEnum);
                            log.info("任务id：{},工作跨：{},工作天车编号：{},双车加料线程任务。判断槽车是否到位，当前槽车到位信号为：{}",taskId,workingSpanNo,workingCarNo,tankCarScanActFinish);

                            //天车模式flag  false:手动  true:自动
                            boolean modelFlag = Boolean.valueOf(this.getValByLabel(modelParamMap));

                            if(!modelFlag){
                                //模式为自动时，线程结束
                                log.info("任务id：{},工作跨：{},工作天车编号：{},双车加料线程任务。判断槽车是否到位时，模式切换至手动模式，线程退出",taskId,workingSpanNo,workingCarNo);
                                SysAddDetailTaskEntity updateTaskEntity = SysAddDetailTaskEntity.builder()
                                        .idKey(idKey).status(TaskStatusEnum.STATUS_ERROR.getStatus()).errMsg("判断槽车是否到位时,天车模式切换至手动模式，任务退出").build();
                                DataUpdateThread.builder().detailTaskService(detailTaskService).sysAddDetailTask(updateTaskEntity).build().start();
                                return;

                            }

//                            if(taskFlag){
//                                throw new AddTaskException("双车加料线程执行任务时，任务监控点位出现故障");
//                            }

                            if(taskFinishFlag){
                                log.error("任务id：{},工作跨：{},工作天车编号：{},双车加料线程任务。判断槽车是否到位。任务标识为已完成",taskId,workingSpanNo,workingCarNo);
                                throw new AddTaskException("双车加料线程执行任务时，任务手动置为完成状态");
                            }


                            if (tankCarScanActFinish){
                                tankCarReadyFlag = true;
                                break;
                            }
                            Thread.sleep(1*1000);
                        }
                    }
                    boolean tankCarFlag = ScanUtils.getTankCarFlag(tankCarNoEnum);
                    if(AddTaskConstant.TANKCAR_SCAN_USE_FLAG && !tankCarFlag){
                        //启用槽车扫描就启动扫描
                        log.info("任务id：{},工作跨：{},工作天车编号：{},双车加料线程任务。异步启动槽车扫描",taskId,workingSpanNo,workingCarNo);
                        ThreadPoolManager.getInstance().execute(AsynTankCarScanThread.builder().tankCarNoEnum(tankCarNoEnum).spanNo(workingSpanNo).build());
                    }
                    msgThread = CarProgressLogThread.builder().carInfo(carPLCInfoEnum.getMacSN())
                            .msg("槽车已到位").build();
                    ThreadPoolManager.getInstance().execute(msgThread);
                    log.info("任务id：{},工作跨：{},工作天车编号：{},双车加料线程任务。槽车已到位",taskId,workingSpanNo,workingCarNo);


                    //判断抓动作是否完成
                    while (true){
                        log.info("任务id：{},工作跨：{},工作天车编号：{},双车加料线程任务。开始判断抓动作是否完成",taskId,workingSpanNo,workingCarNo);

                        carParamMap.put(GlobalConstant.STRING_LABEL, macSN + GlobalConstant.SUCK_FINISH_LABEL);

                        boolean suckFlag = Boolean.valueOf(this.getValByLabel(carParamMap));
                        //天车模式点位读取
                        boolean modelFlag = Boolean.valueOf(this.getValByLabel(modelParamMap));
//                        if(taskFlag){
//                            throw new AddTaskException("双车加料线程执行任务时，任务监控点位出现故障");
//                        }

                        if(taskFinishFlag){
                            log.error("任务id：{},工作跨：{},工作天车编号：{},双车加料线程任务。开始判断抓动作是否完成。任务标识为已完成",taskId,workingSpanNo,workingCarNo);
                            throw new AddTaskException("双车加料线程执行任务时，任务手动置为完成状态");
                        }


//                        suckFlag = true;
//                        modelFlag = true;
                        if(!modelFlag){
                            //模式为自动时，线程结束
                            log.info("任务id：{},工作跨：{},工作天车编号：{},双车加料线程任务。吸料动作已完成，模式切换至手动模式，线程退出",taskId,workingSpanNo,workingCarNo);
                            SysAddDetailTaskEntity updateTaskEntity = SysAddDetailTaskEntity.builder()
                                    .idKey(idKey).status(TaskStatusEnum.STATUS_ERROR.getStatus()).errMsg("天车模式切换至手动模式，任务退出").build();
                            DataUpdateThread.builder().detailTaskService(detailTaskService).sysAddDetailTask(updateTaskEntity).build().start();
                            return;
                        }

                        if(suckFlag){
                            log.info("任务id：{},工作跨：{},工作天车编号：{},双车加料线程任务。吸料动作已完成，复位开始",taskId,workingSpanNo,workingCarNo);

                            //天车吸料任务执行复位
                            Object[] carExecuteInfo = carPLCInfoEnum.getPLCInfoArray()[5];
                            PLCWriteRequestParamBO paramBO = PLCWriteRequestParamBO.builder().dataType((Integer) carExecuteInfo[1])
                                    .address((String) carExecuteInfo[0]).macSN(macSN).label((String) carExecuteInfo[2]).build();
                            paramBO.setValue(AddTaskConstant.CAR_FORBID_MOVE);
                            PLCHttpsUtils.write(RemoteURLConstant.URL_WRITEBC,paramBO);
                            log.info("任务id：{},工作跨：{},工作天车编号：{},双车加料线程任务。吸料动作已完成，复位完成",taskId,workingSpanNo,workingCarNo);
                            endDate = LocalDateTime.now();
                            int timeInterval = DateUtils.getTimeInterval(startDate, endDate);
                            SysPLCRecordEntity plcUpdateEntity = SysPLCRecordEntity.builder().idKey(plcRecord.getIdKey())
                                    .status(PLCRecordStatusEnum.PLC_STATUS_SUCC.getStatus()).spendTime(timeInterval).build();
                            plcRecordService.updateById(plcUpdateEntity);
                            break;
                        }
                        Thread.sleep(1*1000);

                    }

                    msgThread = CarProgressLogThread.builder().carInfo(carPLCInfoEnum.getMacSN())
                            .msg("天车抓取动作已完成").build();
                    ThreadPoolManager.getInstance().execute(msgThread);



                    //4.、放动作
                    //业务逻辑执行
                    lock.lock();
                    log.info("任务id：{},工作跨：{},工作天车编号：{},双车加料线程任务。开始获取放点",taskId,workingSpanNo,workingCarNo);

                    otherPosition = AddTaskUtil.getCarIndex(otherKey);
                    //Coord tankCarPoint = ScanUtils.getTankCarPoint(tankCarNoEnum.getTankCarNo(),carPLCInfoEnum.getScanType());
                    //Coord tankCarPoint = ScanUtils.getTestTankCarPoint(workingSpanNo,tankCarNoEnum,taskMaterialBO.getTest());
                    //todo 使用槽车扫描
                    Coord tankCarPoint = ScanUtils.getTankCarPoint(tankCarNoEnum, workingSpanNo);

                    if(tankCarPoint == null){
                        throw new AddTaskException("没有获取到槽车扫描点数据");
                    }

//                    Coord tankCarPoint = new Coord();
//                    tankCarPoint.setY(10000);
//                    tankCarPoint.setX(94000);
//                    tankCarPoint.setZ(10000);

//                    Coord tankCarPoint = new Coord();
//                    if(workingCarNo.equals("1")){
//                        tankCarPoint.setX(8888);
//                    }
//
//                    if(workingCarNo.equals("2")){
//                        tankCarPoint.setX(222);
//                    }
                    //记录PLC表
                    startDate = LocalDateTime.now();
                    plcRecord = SysPLCRecordEntity.builder().taskId(taskId).relationIdKey(String.valueOf(idKey)).carName(carPLCInfoEnum.getMacSN())
                            .indexInfo(tankCarPoint.getIndexInfo()).actionInfo(AddTaskConstant.ACT_PUT).targetInfo("槽车："+tankCarNoEnum.getTankName()).build();
                    plcRecordService.save(plcRecord);

                    isConflict = comparePosition(workingCarEnum, tankCarPoint.getX(), otherPosition);
                    if(isConflict){
                        log.info("任务id：{},工作跨：{},工作天车编号：{},双车加料线程任务。放点不冲突",taskId,workingSpanNo,workingCarNo);
                        this.lastAct = AddTaskConstant.ACT_MOVE;
                        AddTaskUtil.updateCarIndex(currKey,tankCarPoint.getX());
                        //3.去放点,获取当前槽车重量信息           label:1号废钢跨天车 + 1号过跨车 + 重量
                        msgThread = CarProgressLogThread.builder().carInfo(carPLCInfoEnum.getMacSN())
                                .msg("天车执行放下动作，不冲突").build();
                        ThreadPoolManager.getInstance().execute(msgThread);
                        carParamMap.put(GlobalConstant.STRING_LABEL, tankCarNoEnum.getWeightLabel());
                        oldWeight = Float.valueOf(this.getValByLabel(carParamMap));
                        //oldWeight = 0;
                        //4.抓动作之后完成后，根据放点坐标是否冲突（要去的坐标，没有则实际位置）。不冲突直接执行。冲突，则判断行动的优先级
                        lock.unlock();
                        //没有冲突
                        taskType = AddTaskConstant.CAR_TASK_TYPE_PUT;
                        taskPlace = AddTaskConstant.CAR_TASK_PLACE_STEEL_CAR;
                        //移动写值操作
                        carRunningFlag = AddTaskUtil.isCarRunningStatus(carSN, carPLCInfoEnum.getMacSN(), carPLCInfoEnum.getOtherMacSN());
//                        carRunningFlag = true;
                        if(!carRunningFlag){
                            throw new AddTaskException("双车执行任务时，双车的大车运行状态不是自动,跨区为："+workingSpanNo);
                        }
                        log.info("任务id：{},工作跨：{},工作天车编号：{},双车加料线程任务。移动写值开始",taskId,workingSpanNo,workingCarNo);
                        this.writeOpt(carPLCInfoEnum,tankCarPoint,taskType,taskPlace);
                        log.info("任务id：{},工作跨：{},工作天车编号：{},双车加料线程任务。移动写值结束",taskId,workingSpanNo,workingCarNo);

                    } else {
                        log.info("任务id：{},工作跨：{},工作天车编号：{},双车加料线程任务。放点冲突。更新的新值为：{}",taskId,workingSpanNo,workingCarNo,tankCarPoint.getX());

                        AddTaskUtil.updateCarIndex(currKey,tankCarPoint.getX());
                        //读取X方向的位置
                        log.info("任务id：{},工作跨：{},工作天车编号：{},双车加料线程任务。放点冲突",taskId,workingSpanNo,workingCarNo);

                        carParamMap.put(GlobalConstant.STRING_LABEL, macSN + GlobalConstant.CAR_X_INDEX_LABEL);
                        int xIndex = Integer.valueOf(this.getValByLabel(carParamMap));
                        //int xIndex = 1;
                        //todo  1000为中间值
                        //有冲突，放的时候，若左车在右边吸料后放料或者右车在左边吸料后放料  此行动优先级最高
                        if((CarEnum.CAR_NO_1 == workingCarEnum && xIndex < 100000) || (CarEnum.CAR_NO_2 == workingCarEnum && xIndex > 100000)){
                            log.info("任务id：{},工作跨：{},工作天车编号：{},双车加料线程任务。放点冲突，优先级高，继续移动",taskId,workingSpanNo,workingCarNo);
                            msgThread = CarProgressLogThread.builder().carInfo(carPLCInfoEnum.getMacSN())
                                    .msg("天车执行放下动作，虽然冲突，但优先级高，本次继续移动").build();
                            ThreadPoolManager.getInstance().execute(msgThread);
                            this.lastAct = AddTaskConstant.ACT_MOVE;
                            lock.unlock();
                            carParamMap.put(GlobalConstant.STRING_LABEL, tankCarNoEnum.getWeightLabel());
                            oldWeight = Float.valueOf(this.getValByLabel(carParamMap));
                            //oldWeight = 0;
                            taskType = AddTaskConstant.CAR_TASK_TYPE_PUT;
                            taskPlace = AddTaskConstant.CAR_TASK_PLACE_STEEL_CAR;
                            //移动写值操作
                            carRunningFlag = AddTaskUtil.isCarRunningStatus(carSN, carPLCInfoEnum.getMacSN(), carPLCInfoEnum.getOtherMacSN());
//                            carRunningFlag = true;
                            if(!carRunningFlag){
                                throw new AddTaskException("双车执行任务时，双车的大车运行状态不是自动,跨区为："+workingSpanNo);
                            }
                            log.info("任务id：{},工作跨：{},工作天车编号：{},双车加料线程任务。移动写值开始",taskId,workingSpanNo,workingCarNo);

                            this.writeOpt(carPLCInfoEnum,tankCarPoint,taskType,taskPlace);
                            log.info("任务id：{},工作跨：{},工作天车编号：{},双车加料线程任务。移动写值结束",taskId,workingSpanNo,workingCarNo);

                            //对方线程进行二次避让
                            if(AddTaskConstant.ACT_AVOID.equals(otherThread.getLastAct())){
                                log.info("任务id：{},工作跨：{},工作天车编号：{},对方线程二次避让，生成唤醒线程",taskId,workingSpanNo,workingCarNo);

                                otherThread.secAvoidFlag = true;
                                //生成特殊额外唤醒对方线程
                                ThreadPoolManager.getInstance().execute(new ExtraTaskWakeThread().builder().carInfo(carPLCInfoEnum.getOtherDesc()).thread(otherThread).build());
                            }

                        } else {
                            log.info("任务id：{},工作跨：{},工作天车编号：{},双车加料线程任务。放点冲突，优先级低，执行避让动作",taskId,workingSpanNo,workingCarNo);

                            //否则避让
                            msgThread = CarProgressLogThread.builder().carInfo(carPLCInfoEnum.getMacSN())
                                    .msg("天车执行放下动作，冲突，执行避让动作").build();
                            ThreadPoolManager.getInstance().execute(msgThread);
                            this.lastAct = AddTaskConstant.ACT_AVOID;
                            if(AddTaskConstant.ACT_AVOID.equals(otherThread.getLastAct())){
                                //两个线程同时为避让，生成被动唤醒线程
                                if(AddTaskUtil.isPassiveThread(workingSpanNo)){
                                    log.info("任务id：{},工作跨：{},工作天车编号：{},双车加料线程任务。天车执行放下动作，冲突，生成被动唤醒对方线程",taskId,workingSpanNo,workingCarNo);
                                    msgThread = CarProgressLogThread.builder().carInfo(carPLCInfoEnum.getMacSN())
                                            .msg("天车执行放下动作，冲突，生成被动唤醒对方线程").build();
                                    ThreadPoolManager.getInstance().execute(msgThread);
                                    TaskWakeThread taskWakeThread = TaskWakeThread.builder().thread(otherThread).carInfo(carPLCInfoEnum.getOtherDesc()).workSpanNo(workingSpanNo).build();
                                    ThreadPoolManager.getInstance().execute(taskWakeThread);
                                }
                            }

                            lock.unlock();
                            AddTaskUtil.updateCarIndex(currKey,tankCarPoint.getX());
                            otherTargetIndex = AddTaskUtil.getCarIndex(otherKey);
                            //移动至对方位置的避让位置
                            taskType = AddTaskConstant.CAR_TASK_TYPE_MOVE;
                            taskPlace = AddTaskConstant.CAR_TASK_PLACE_MATERIAL;
                            //安全距离设置
                            //判断是一号车？ 另一台车的目标位置 - 安全距离  ： 另一台车的目标位置 + 安全距离
                            avoidIndex = workingCarEnum.getOtherCarNo().equals(CarEnum.CAR_NO_1.getCarNo()) ? otherTargetIndex - AddTaskConstant.SAFE_DISTANCE :
                                    otherTargetIndex + AddTaskConstant.SAFE_DISTANCE;
                            Coord avoidCoord = new Coord();
                            avoidCoord.setX(avoidIndex);
                            avoidCoord.setY(tankCarPoint.getY());
                            avoidCoord.setZ(AddTaskConstant.SAFE_HEIGHT_DISTANCE);
                            //移动写值操作
                            carRunningFlag = AddTaskUtil.isCarRunningStatus(carSN, carPLCInfoEnum.getMacSN() ,carPLCInfoEnum.getOtherMacSN());
//                            carRunningFlag = true;
                            if(!carRunningFlag){
                                throw new AddTaskException("双车执行任务时，双车的大车运行状态不是自动,跨区为："+workingSpanNo);
                            }
                            this.writeOpt(carPLCInfoEnum,avoidCoord,taskType,taskPlace);

                            msgThread = CarProgressLogThread.builder().carInfo(carPLCInfoEnum.getMacSN())
                                    .msg("天车执行放下动作,因冲突判断避让动作是否完成").build();
                            ThreadPoolManager.getInstance().execute(msgThread);
                            //判断避让动作是否完成
                            while (true){
                                log.info("任务id：{},工作跨：{},工作天车编号：{},双车加料线程任务。放点冲突，开始判断避让动作是否完成",taskId,workingSpanNo,workingCarNo);

                                carParamMap.put(GlobalConstant.STRING_LABEL, macSN + GlobalConstant.MOVE_FINISH_LABEL);
                                boolean moveFlag = Boolean.valueOf(this.getValByLabel(carParamMap));
                                //天车模式点位读取
                                boolean modelFlag = Boolean.valueOf(this.getValByLabel(modelParamMap));
//                                if(taskFlag){
//                                    throw new AddTaskException("双车加料线程执行任务时，任务监控点位出现故障");
//                                }

                                if(taskFinishFlag){
                                    log.error("任务id：{},工作跨：{},工作天车编号：{},双车加料线程任务。放点冲突，开始判断避让动作是否完成。任务标识为已完成",taskId,workingSpanNo,workingCarNo);
                                    throw new AddTaskException("双车加料线程执行任务时，任务手动置为完成状态");
                                }

//                                moveFlag = true;
//                                modelFlag = true;
                                if(!modelFlag){
                                    //模式为自动时，线程结束
                                    log.info("任务id：{},工作跨：{},工作天车编号：{},双车加料线程任务。放点冲突，模式切换至手动模式，线程退出",taskId,workingSpanNo,workingCarNo);
                                    SysAddDetailTaskEntity updateTaskEntity = SysAddDetailTaskEntity.builder()
                                            .idKey(idKey).status(TaskStatusEnum.STATUS_ERROR.getStatus()).errMsg("天车模式切换至手动模式，任务退出").build();
                                    DataUpdateThread.builder().detailTaskService(detailTaskService).sysAddDetailTask(updateTaskEntity).build().start();
                                    return;
                                }
                                if(moveFlag){
                                    log.info("任务id：{},工作跨：{},工作天车编号：{},双车加料线程任务。放点冲突,避让动作完成",taskId,workingSpanNo,workingCarNo);

                                    Object[] carExecuteInfo = carPLCInfoEnum.getPLCInfoArray()[5];
                                    //天车动作执行复位
                                    PLCWriteRequestParamBO paramBO = PLCWriteRequestParamBO.builder().dataType((Integer) carExecuteInfo[1])
                                            .address((String) carExecuteInfo[0]).macSN(macSN).label((String) carExecuteInfo[2]).build();
                                    paramBO.setValue(AddTaskConstant.CAR_FORBID_MOVE);
                                    PLCHttpsUtils.write(RemoteURLConstant.URL_WRITEBC,paramBO);

                                    break;
                                }
                                Thread.sleep(1*1000);

                            }
                            msgThread = CarProgressLogThread.builder().carInfo(carPLCInfoEnum.getMacSN())
                                    .msg("天车执行放下动作,因冲突判断避让动作已完成，准备进入等待状态").build();
                            ThreadPoolManager.getInstance().execute(msgThread);
                            //等待唤醒
                            synchronized (this){
                                //等待唤醒
                                msgThread = CarProgressLogThread.builder().carInfo(carPLCInfoEnum.getMacSN())
                                        .msg("天车执行放下动作,因冲突判断避让动作已完成，进入等待状态").build();
                                ThreadPoolManager.getInstance().execute(msgThread);
                                this.wait();

                            }
                            log.info("任务id：{},工作跨：{},工作天车编号：{},双车加料线程任务。放点冲突，第一次被唤醒",taskId,workingSpanNo,workingCarNo);

                            if(secAvoidFlag){
                                //二次避让，放动作
                                msgThread = CarProgressLogThread.builder().carInfo(carPLCInfoEnum.getMacSN())
                                        .msg("天车执行放下动作，因冲突避让动作已完成，被唤醒。需要进行二次避让").build();
                                ThreadPoolManager.getInstance().execute(msgThread);
                                log.info("任务id：{},工作跨：{},工作天车编号：{},双车加料线程任务。放点冲突，线程被唤醒，需要进行二次避让",taskId,workingSpanNo,workingCarNo);
                                otherTargetIndex = AddTaskUtil.getCarIndex(otherKey);
                                log.info("任务id：{},工作跨：{},工作天车编号：{},双车加料线程任务。放点冲突，线程被唤醒，需要进行二次避让的得到对方坐标值：{}",taskId,workingSpanNo,workingCarNo,otherTargetIndex);

                                taskType = AddTaskConstant.CAR_TASK_TYPE_MOVE;
                                taskPlace = AddTaskConstant.CAR_TASK_PLACE_MATERIAL;

                                //安全距离设置
                                //判断是一号车？ 另一台车的目标位置 - 安全距离  ： 另一台车的目标位置 + 安全距离
                                avoidIndex = workingCarEnum.getOtherCarNo().equals(CarEnum.CAR_NO_1.getCarNo()) ? otherTargetIndex - AddTaskConstant.SAFE_DISTANCE :
                                        otherTargetIndex + AddTaskConstant.SAFE_DISTANCE;
                                log.info("任务id：{},工作跨：{},工作天车编号：{},双车加料线程任务。放点不冲突，线程被唤醒，需要进行二次避让的避让坐标值：{}",taskId,workingSpanNo,workingCarNo,avoidIndex);
                                Coord secAvoidCoord = new Coord();
                                secAvoidCoord.setX(avoidIndex);
                                secAvoidCoord.setY(tankCarPoint.getY());
                                secAvoidCoord.setZ(AddTaskConstant.SAFE_HEIGHT_DISTANCE);
                                //移动写值操作
                                carRunningFlag = AddTaskUtil.isCarRunningStatus(carSN, carPLCInfoEnum.getMacSN() ,carPLCInfoEnum.getOtherMacSN());
//                                carRunningFlag = true;
                                if(!carRunningFlag){
                                    throw new AddTaskException("双车执行任务时，双车的大车运行状态不是自动,跨区为："+workingSpanNo);
                                }
                                log.info("任务id：{},工作跨：{},工作天车编号：{},双车加料线程任务。移动写值开始",taskId,workingSpanNo,workingCarNo);

                                this.writeOpt(carPLCInfoEnum,secAvoidCoord,taskType,taskPlace);
                                log.info("任务id：{},工作跨：{},工作天车编号：{},双车加料线程任务。移动写值结束",taskId,workingSpanNo,workingCarNo);

                                //判断二次避让动作是否完成
                                while (true){
                                    log.info("任务id：{},工作跨：{},工作天车编号：{},双车加料线程任务。放点冲突，开始判断二次避让动作是否完成",taskId,workingSpanNo,workingCarNo);

                                    carParamMap.put(GlobalConstant.STRING_LABEL, macSN + GlobalConstant.MOVE_FINISH_LABEL);
                                    boolean moveFlag = Boolean.valueOf(this.getValByLabel(carParamMap));
                                    //天车模式点位读取
                                    boolean modelFlag = Boolean.valueOf(this.getValByLabel(modelParamMap));
//                                    if(taskFlag){
//                                        throw new AddTaskException("双车加料线程执行任务时，任务监控点位出现故障");
//                                    }

                                    if(taskFinishFlag){
                                        log.error("任务id：{},工作跨：{},工作天车编号：{},双车加料线程任务。放点冲突，开始判断二次避让动作是否完成。任务标识为已完成",taskId,workingSpanNo,workingCarNo);
                                        throw new AddTaskException("双车加料线程执行任务时，任务手动置为完成状态");
                                    }

//                                    moveFlag = true;
//                                    modelFlag = true;
                                    if(!modelFlag){
                                        //模式为自动时，线程结束
                                        log.info("任务id：{},工作跨：{},工作天车编号：{},双车加料线程任务。放点冲突，模式切换至手动模式，线程退出",taskId,workingSpanNo,workingCarNo);
                                        SysAddDetailTaskEntity updateTaskEntity = SysAddDetailTaskEntity.builder()
                                                .idKey(idKey).status(TaskStatusEnum.STATUS_ERROR.getStatus()).errMsg("天车模式切换至手动模式，任务退出").build();
                                        DataUpdateThread.builder().detailTaskService(detailTaskService).sysAddDetailTask(updateTaskEntity).build().start();
                                        return;
                                    }
                                    if(moveFlag){
                                        log.info("任务id：{},工作跨：{},工作天车编号：{},双车加料线程任务。放点冲突,二次避让动作完成",taskId,workingSpanNo,workingCarNo);
                                        //自身二次避让标识回位
                                        secAvoidFlag = false;
                                        Object[] carExecuteInfo = carPLCInfoEnum.getPLCInfoArray()[5];
                                        //天车动作执行复位
                                        PLCWriteRequestParamBO paramBO = PLCWriteRequestParamBO.builder().dataType((Integer) carExecuteInfo[1])
                                                .address((String) carExecuteInfo[0]).macSN(macSN).label((String) carExecuteInfo[2]).build();
                                        paramBO.setValue(AddTaskConstant.CAR_FORBID_MOVE);
                                        PLCHttpsUtils.write(RemoteURLConstant.URL_WRITEBC,paramBO);
                                        log.info("任务id：{},工作跨：{},工作天车编号：{},双车加料线程任务。放点冲突,二次避让动作完成，复位结束",taskId,workingSpanNo,workingCarNo);

                                        break;
                                    }
                                    Thread.sleep(1*1000);

                                }

                                synchronized (this){
                                    //等待唤醒
                                    msgThread = CarProgressLogThread.builder().carInfo(carPLCInfoEnum.getMacSN())
                                            .msg("天车执行放下动作,因冲突执行二次避让动作，进入等待状态").build();
                                    ThreadPoolManager.getInstance().execute(msgThread);
                                    this.wait();
                                }
                                log.info("任务id：{},工作跨：{},工作天车编号：{},双车加料线程任务。放点冲突，第二次被唤醒",taskId,workingSpanNo,workingCarNo);


                            }

                            lock.lock();
                            this.lastAct = AddTaskConstant.ACT_MOVE;
                            msgThread = CarProgressLogThread.builder().carInfo(carPLCInfoEnum.getMacSN())
                                    .msg("天车执行放下动作，因冲突避让动作已完成，被唤醒。移动至放点位置").build();
                            ThreadPoolManager.getInstance().execute(msgThread);
                            log.info("任务id：{},工作跨：{},工作天车编号：{},双车加料线程任务。放点不冲突，线程被唤醒，移动至放点位置",taskId,workingSpanNo,workingCarNo);
                            carParamMap.put(GlobalConstant.STRING_LABEL, tankCarNoEnum.getWeightLabel());
                            oldWeight = Float.valueOf(this.getValByLabel(carParamMap));
                            //oldWeight = 0;
                            lock.unlock();
                            //todo 移动至此次的目标位置
                            taskType = AddTaskConstant.CAR_TASK_TYPE_PUT;
                            taskPlace = AddTaskConstant.CAR_TASK_PLACE_STEEL_CAR;
                            //移动写值操作
                            carRunningFlag = AddTaskUtil.isCarRunningStatus(carSN, carPLCInfoEnum.getMacSN(), carPLCInfoEnum.getOtherMacSN());
//                            carRunningFlag = true;
                            if(!carRunningFlag){
                                throw new AddTaskException("双车执行任务时，双车的大车运行状态不是自动,跨区为："+workingSpanNo);
                            }
                            log.info("任务id：{},工作跨：{},工作天车编号：{},双车加料线程任务。移动写值开始",taskId,workingSpanNo,workingCarNo);

                            this.writeOpt(carPLCInfoEnum,tankCarPoint,taskType,taskPlace);
                            log.info("任务id：{},工作跨：{},工作天车编号：{},双车加料线程任务。移动写值结束",taskId,workingSpanNo,workingCarNo);

                        }
                    }


                    //判断放动作是否完成
                    msgThread = CarProgressLogThread.builder().carInfo(carPLCInfoEnum.getMacSN())
                            .msg("判断天车放下动作是否完成").build();
                    ThreadPoolManager.getInstance().execute(msgThread);
                    while (true){
                        log.info("任务id：{},工作跨：{},工作天车编号：{},双车加料线程任务。判断放动作是否完成",taskId,workingSpanNo,workingCarNo);

                        carParamMap.put(GlobalConstant.STRING_LABEL, macSN + GlobalConstant.PUT_FINISH_LABEL);
                        boolean putFlag = Boolean.valueOf(this.getValByLabel(carParamMap));
                        //天车模式点位读取
                        boolean modelFlag = Boolean.valueOf(this.getValByLabel(modelParamMap));
//                        if(taskFlag){
//                            throw new AddTaskException("双车加料线程执行任务时，任务监控点位出现故障");
//                        }

                        if(taskFinishFlag){
                            log.error("任务id：{},工作跨：{},工作天车编号：{},双车加料线程任务。判断放动作是否完成。任务标识为已完成",taskId,workingSpanNo,workingCarNo);
                            throw new AddTaskException("双车加料线程执行任务时，任务手动置为完成状态");
                        }

//                        modelFlag = true;
//                        putFlag = true;
                        if(!modelFlag){
                            //模式为自动时，线程结束
                            log.info("任务id：{},工作跨：{},工作天车编号：{},双车加料线程任务。放下动作完成，模式切换至手动模式，线程退出",taskId,workingSpanNo,workingCarNo);
                            SysAddDetailTaskEntity updateTaskEntity = SysAddDetailTaskEntity.builder()
                                    .idKey(idKey).status(TaskStatusEnum.STATUS_ERROR.getStatus()).errMsg("天车模式切换至手动模式，任务退出").build();
                            DataUpdateThread.builder().detailTaskService(detailTaskService).sysAddDetailTask(updateTaskEntity).build().start();
                            return;
                        }


                        if(putFlag){
                            log.info("任务id：{},工作跨：{},工作天车编号：{},双车加料线程任务。放下动作完成",taskId,workingSpanNo,workingCarNo);

                            //天车动作执行复位
                            Object[] carExecuteInfo = carPLCInfoEnum.getPLCInfoArray()[5];
                            PLCWriteRequestParamBO paramBO = PLCWriteRequestParamBO.builder().dataType((Integer) carExecuteInfo[1])
                                    .address((String) carExecuteInfo[0]).macSN(macSN).label((String) carExecuteInfo[2]).build();
                            paramBO.setValue(AddTaskConstant.CAR_FORBID_MOVE);
                            PLCHttpsUtils.write(RemoteURLConstant.URL_WRITEBC,paramBO);
                            log.info("任务id：{},工作跨：{},工作天车编号：{},双车加料线程任务。放下动作完成。复位结束",taskId,workingSpanNo,workingCarNo);

                            break;
                        }
                        Thread.sleep(1*1000);

                    }
                    msgThread = CarProgressLogThread.builder().carInfo(carPLCInfoEnum.getMacSN())
                            .msg("天车放下动作已完成，计算重量数据").build();
                    ThreadPoolManager.getInstance().execute(msgThread);
                    log.info("任务id：{},工作跨：{},工作天车编号：{},计算重量",taskId,workingSpanNo,workingCarNo);

                    //3.去放点,获取当前槽车重量信息           label:重量
                    lock.lock();
                    carParamMap.put(GlobalConstant.STRING_LABEL, tankCarNoEnum.getWeightLabel());
                    nowWeight = Float.valueOf(this.getValByLabel(carParamMap));
                    //nowWeight = 0;
                    lock.unlock();
                    //读取该物料已加的重量
                    SysAddDetailTaskEntity addDetailTaskEntity = detailTaskService.getMaterial(taskId, taskMaterial.getWorkinMaterialNo());
                    float addWeight = nowWeight - oldWeight;
                    float actWeight = addDetailTaskEntity.getActualWeight() + addWeight;
                    endDate = LocalDateTime.now();
                    int timeInterval = DateUtils.getTimeInterval(startDate, endDate);
                    //更新PLC操作
                    SysPLCRecordEntity plcUpdateEntity = SysPLCRecordEntity.builder().idKey(plcRecord.getIdKey())
                            .status(PLCRecordStatusEnum.PLC_STATUS_SUCC.getStatus()).spendTime(timeInterval).addWeight(actWeight).build();
                    plcRecordService.updateById(plcUpdateEntity);
                    if(TaskStatusEnum.STATUS_COMPLETE.getStatus().equals(addDetailTaskEntity.getStatus())){
                        log.info("任务id：{},工作跨：{},工作天车编号：{},双车加料线程任务,任务状态已翻转为完成状态。抓取物料：{},结束",taskId,workingSpanNo,workingCarNo,taskMaterial.getWorkinMaterialNo());

                        actWeight = Float.valueOf(String.format("%.6f", actWeight));
                        SysAddDetailTaskEntity updateEntity = SysAddDetailTaskEntity.builder().idKey(addDetailTaskEntity.getIdKey())
                                .status(TaskStatusEnum.STATUS_COMPLETE.getStatus()).errMsg("任务状态手动翻转为完成状态").actualWeight(actWeight).build();
                        DataUpdateThread.builder().detailTaskService(detailTaskService).sysAddDetailTask(updateEntity).build().start();
                        msgThread = CarProgressLogThread.builder().carInfo(carPLCInfoEnum.getMacSN())
                                .msg("天车本次子任务"+ addDetailTaskEntity.getMaterialName() +"任务状态已手动翻转完成").build();
                        ThreadPoolManager.getInstance().execute(msgThread);
                        break;
                    }

                    if(Math.abs(actWeight - addDetailTaskEntity.getTargetWeight()) < 1 || actWeight >  addDetailTaskEntity.getTargetWeight()){
                        log.info("任务id：{},工作跨：{},工作天车编号：{},双车加料线程任务。抓取物料：{}结束",taskId,workingSpanNo,workingCarNo,taskMaterial.getWorkinMaterialNo());

                        actWeight = Float.valueOf(String.format("%.6f", actWeight));
                        SysAddDetailTaskEntity updateEntity = SysAddDetailTaskEntity.builder().idKey(addDetailTaskEntity.getIdKey())
                                .status(TaskStatusEnum.STATUS_COMPLETE.getStatus()).errMsg(null).actualWeight(actWeight).build();
                        DataUpdateThread.builder().detailTaskService(detailTaskService).sysAddDetailTask(updateEntity).build().start();
                        msgThread = CarProgressLogThread.builder().carInfo(carPLCInfoEnum.getMacSN())
                                .msg("天车本次子任务"+ addDetailTaskEntity.getMaterialName() +"完成").build();
                        ThreadPoolManager.getInstance().execute(msgThread);
                        break;

                    }
                    msgThread = CarProgressLogThread.builder().carInfo(carPLCInfoEnum.getMacSN())
                            .msg("天车重量计算结束，单次抓取放下完成，执行下一次动作").build();
                    ThreadPoolManager.getInstance().execute(msgThread);
                    log.info("任务id：{},工作跨：{},工作天车编号：{},单词抓取放下完成，执行下一次动作",taskId,workingSpanNo,workingCarNo);

                    //否则更新数据库的重量信息，继续抓物料
                    actWeight = Float.valueOf(String.format("%.6f", actWeight));
                    SysAddDetailTaskEntity updateTaskEntity = SysAddDetailTaskEntity.builder()
                            .idKey(addDetailTaskEntity.getIdKey()).actualWeight(actWeight).build();
                    DataUpdateThread.builder().detailTaskService(detailTaskService).sysAddDetailTask(updateTaskEntity).build().start();

                }

            }
        } catch (Exception e){
            log.error("任务id：{}双车加料线程任务，天车编号：{}。运行出错",taskId,workingCarNo,e);
            String errMsg = e.getMessage();
            if(errMsg == null){
                errMsg = "双车加料任务运行出错，请查看日志";
            }
            errMsg = errMsg.length() > 200 ? errMsg.substring(0,200) : errMsg;
            SysAddDetailTaskEntity errEntity = SysAddDetailTaskEntity.builder().idKey(idKey)
                    .status(TaskStatusEnum.STATUS_ERROR.getStatus()).errMsg(errMsg).build();
            detailTaskService.updateById(errEntity);
            SysTaskErrorInfoEntity sysTaskErrorInfoEntity = SysTaskErrorInfoEntity.builder().carName(carPLCInfoEnum.getMacSN()).taskId(taskMaterialBO.getTaskId()).errMsg(errMsg).build();
            ThreadPoolManager.getInstance().execute(AddTaskRecordErrorInfoThread.builder().taskErrorInfoEntity(sysTaskErrorInfoEntity).build());
            TaskExecutionWebSocketService socketService = SpringUtils.getBean(TaskExecutionWebSocketService.class);
            Map map = new HashMap(2);
            map.put("code","20");
            map.put("data",macSN+":执行任务id:"+idKey+",出现异常。出错原因："+errMsg);
            socketService.sendMessage(map);
            try {
                log.info("出现异常,当前天车位置更新为当前的位置!!!");

                //异常退出时，大车实时位置更新为当前位置
                carParamMap.put(GlobalConstant.STRING_LABEL,carPLCInfoEnum.getMacSN() + GlobalConstant.CAR_X_INDEX_LABEL);

                int xIndex = Integer.valueOf(this.getValByLabel(carParamMap));

                AddTaskUtil.updateCarIndex(currKey,xIndex);
                Object[] carExecuteInfo = carPLCInfoEnum.getPLCInfoArray()[5];
                //天车动作执行复位
                PLCWriteRequestParamBO paramBO = PLCWriteRequestParamBO.builder().dataType((Integer) carExecuteInfo[1])
                        .address((String) carExecuteInfo[0]).macSN(macSN).label((String) carExecuteInfo[2]).build();
                paramBO.setValue(AddTaskConstant.CAR_FORBID_MOVE);

                PLCHttpsUtils.write(RemoteURLConstant.URL_WRITEBC,paramBO);
            } catch (Exception ee){
                log.error("线程最后执行天车运行点位复位运行错误",e);

            }


        }finally {
            try {
                AddTaskConstant.CAR_THREAD_MAP.remove(carPLCInfoEnum.getMacSN());
                taskFinishFlag = true;
                lock.unlock();
            } catch (Exception e){
                log.error("线程最后执行复位代码异常",e);
            }

        }

    }

    private String getValByLabel(Map<String, String> paramMap) throws IOException {

        ResponseLabelDataBO responseLabelDataBO = PLCHttpsUtils.sendPost(RemoteURLConstant.URL_READBC, paramMap, ResponseLabelDataBO.class);
        Map<String, String> content1 = responseLabelDataBO.getContent();
        String res = content1 != null ? content1.get("currentVal").toLowerCase(): null;
        return res;
    }

    private void writeOpt(CarPLCInfoEnum carPLCInfoEnum, Coord coord,String taskType,String taskPlace) throws Exception {
        log.info("天车:{},写多个值开始",carPLCInfoEnum.getMacSN());

        //plcInfoArray  二维数组  大车目标坐标[] 小车目标坐标[]  起升目标坐标[] 作业类型[]  作业地址[] 任务运行[]
        Object[][] plcInfoArray = carPLCInfoEnum.getPLCInfoArray();
        for(int i = 0;i < plcInfoArray.length;i++){
            //info  一位数组地[址,数据类型,label]
            Object[] info = plcInfoArray[i];
            PLCWriteRequestParamBO paramBO = PLCWriteRequestParamBO.builder().macSN(carPLCInfoEnum.getMacSN()).address((String) info[0])
                    .dataType((Integer) info[1]).label((String) info[2]).build();
            paramBO.setValue(this.getValue(taskType,taskPlace,coord,i));
            log.info("第"+ i +"次写值对象是:{}",paramBO);
            if(i == plcInfoArray.length - 1){
                log.info("天车:{},前五个值已完成写值操作",carPLCInfoEnum.getMacSN());
                //当写任务运行时,先读取数据，判断数值是否都写成功了
                for(int j = 0;j < i;j++){
                    Object[] readInfo = plcInfoArray[j];
                    Map<String, String> snMap = SystemUtils.Sys_carInfo.get(ConfigConstant.CONFIG_TYPE_CAR_BAK_SN);
                    String sn = snMap.get(carPLCInfoEnum.getMacSN());
                    String target = this.getValue(taskType, taskPlace, coord, j);
                    boolean isSuccess = PLCHttpsUtils.valIsSuccess(sn, (String) readInfo[2], target);
                    if(!isSuccess){
                        log.info("天车:{},标签值：{},存在未成功，重新写值开始",carPLCInfoEnum.getMacSN(), readInfo[2]);
                        PLCWriteRequestParamBO secondParamBO = PLCWriteRequestParamBO.builder().macSN(carPLCInfoEnum.getMacSN()).address((String) readInfo[0])
                                .dataType((Integer) readInfo[1]).label((String) readInfo[2]).build();
                        secondParamBO.setValue(this.getValue(taskType,taskPlace,coord,j));
                        PLCHttpsUtils.write(RemoteURLConstant.URL_WRITEBC,secondParamBO);
                        log.info("天车:{},标签值：{},存在未成功，重新写值完成",carPLCInfoEnum.getMacSN(), readInfo[2]);
                    }
                }
                log.info("天车:{},开始写最后一个值",carPLCInfoEnum.getMacSN());
                PLCHttpsUtils.write(RemoteURLConstant.URL_WRITEBC,paramBO);
                log.info("天车:{},结束写最后一个值",carPLCInfoEnum.getMacSN());
            } else {
                PLCHttpsUtils.writeMoreVal(RemoteURLConstant.URL_WRITEBC,paramBO);
            }
        }
        log.info("天车:{},写多个值结束",carPLCInfoEnum.getMacSN());

    }


    public void goSafePosition(CarPLCInfoEnum carPLCInfoEnum) throws Exception {

        Object[][] safeArray = carPLCInfoEnum.getCarSafeIndexEnum().getSafeArray();
        for(int i = 0;i < safeArray.length;i++){
            //info  一位数组[地址,数据类型,label]
            Object[] info = safeArray[i];
            PLCWriteRequestParamBO paramBO = PLCWriteRequestParamBO.builder().macSN(carPLCInfoEnum.getMacSN()).address((String) info[0])
                    .dataType((Integer) info[1]).label((String) info[2]).build();
            paramBO.setValue(String.valueOf(info[3]));
            if(i == 5){
                //当写任务运行时,先读取数据，判断数值是否都写成功了
                for(int j = 0;j < i;j++){
                    Object[] readInfo = safeArray[j];
                    Map<String, String> snMap = SystemUtils.Sys_carInfo.get(ConfigConstant.CONFIG_TYPE_CAR_BAK_SN);
                    String sn = snMap.get(carPLCInfoEnum.getMacSN());
                    String target = String.valueOf(readInfo[3]);
                    boolean isSuccess = PLCHttpsUtils.valIsSuccess(sn, (String) readInfo[2], target);
                    if(!isSuccess){
                        PLCWriteRequestParamBO secondParamBO = PLCWriteRequestParamBO.builder().macSN(carPLCInfoEnum.getMacSN()).address((String) readInfo[0])
                                .dataType((Integer) readInfo[1]).label((String) readInfo[2]).build();
                        secondParamBO.setValue(target);
                        PLCHttpsUtils.write(RemoteURLConstant.URL_WRITEBC,secondParamBO);
                    }
                }
                PLCHttpsUtils.write(RemoteURLConstant.URL_WRITEBC,paramBO);
            } else {
                PLCHttpsUtils.writeMoreVal(RemoteURLConstant.URL_WRITEBC,paramBO);
            }
        }

    }

    private String getValue(String taskType, String taskPlace, Coord grabPoint, int i) {

        switch (i){
            case 0:
                return String.valueOf(grabPoint.getX());
            case 1:
                return String.valueOf(grabPoint.getY());
            case 2:
                return String.valueOf(grabPoint.getZ());
            case 3:
                return taskType;
            case 4:
                return taskPlace;
            case 5:
                return AddTaskConstant.CAR_ALLOW_MOVE;
        }
        return null;
    }

    /**
     * 判断辆车的目标位置是否冲突
     * @param curCar
     * @param curPosition
     * @param otherPosition
     * @return  true:没有冲突   false：有冲突
     */
    private boolean comparePosition(CarEnum curCar,int curPosition,Integer otherPosition){


        //todo i为安全距离
        int i = AddTaskConstant.SAFE_DISTANCE;
        if(otherPosition == null){
            //空值代表暂时没有移动，另一台车在安全位置
            return true;
        }
        if(curCar.getCarNo() == CarEnum.CAR_NO_1.getCarNo()){
            //代表当前天车为右侧天车
            if(curPosition > otherPosition &&  curPosition - otherPosition >= i){
                return true;
            }


            return false;
        } else {
            //代表当前天车为左侧天车
            if(curPosition < otherPosition &&  otherPosition - curPosition >= i){
                return true;
            }
            return false;
        }
    }

}
